﻿using System.Windows.Media;
using System.Collections.Generic;

namespace System.Windows
{
    public static class VisualTreeExtensions
    {
        public static IEnumerable<DependencyObject> GetChildren(this DependencyObject depObject)
        {
            int count = depObject.GetChildrenCount();
            for (int i = 0; i < count; i++)
            {
                yield return VisualTreeHelper.GetChild(depObject, i);
            }
        }
        
        public static DependencyObject GetChild(this DependencyObject depObject, int childIndex)
        {
            return VisualTreeHelper.GetChild(depObject, childIndex);
        }

        public static DependencyObject GetChild(this DependencyObject depObject, string name)
        {
            return depObject.GetChild(name, false);
        }

        public static DependencyObject GetChild(this DependencyObject depObject, string name, bool recursive)
        {
            foreach (var child in depObject.GetChildren())
            {
                var element = child as FrameworkElement;                    
                if (element != null)
                {
                    if (element.Name == name)                                           // If its a FrameworkElement check Name
                        return element;
                    var innerElement = element.FindName(name) as DependencyObject;      // Try to get it using FindByName might be more efficient
                    if (innerElement != null)
                        return innerElement;
                }
                if (recursive)                                                          // If it's recursive search through its children
                {
                    var innerChild = child.GetChild(name, true);
                    if (innerChild != null)
                        return innerChild;
                }
            }
            return null;
        }

        public static T FindParentOfType<T>(this FrameworkElement element)
        {
            var parent = VisualTreeHelper.GetParent(element) as FrameworkElement;

            while (parent != null)
            {
                if (parent is T)
                    return (T)(object)parent;

                parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
            }
            return default(T);
        }

        // Methods
        public static List<T> GetChildrenByType<T>(this UIElement element) where T : UIElement
        {
            return element.GetChildrenByType<T>(null);
        }

        public static List<T> GetChildrenByType<T>(this UIElement element, Func<T, bool> condition) where T : UIElement
        {
            List<T> results = new List<T>();
            GetChildrenByType<T>(element, condition, results);
            return results;
        }

        private static void GetChildrenByType<T>(UIElement element, Func<T, bool> condition, List<T> results) where T : UIElement
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                UIElement child = VisualTreeHelper.GetChild(element, i) as UIElement;
                if (child != null)
                {
                    T t = child as T;
                    if (t != null)
                    {
                        if (condition == null)
                        {
                            results.Add(t);
                        }
                        else if (condition(t))
                        {
                            results.Add(t);
                        }
                    }
                    GetChildrenByType<T>(child, condition, results);
                }
            }
        }

        public static bool HasChildrenByType<T>(this UIElement element, Func<T, bool> condition) where T : UIElement
        {
            return (element.GetChildrenByType<T>(condition).Count != 0);
        }

        public static int GetChildrenCount(this DependencyObject depObject)
        {
            return VisualTreeHelper.GetChildrenCount(depObject);
        }

        public static DependencyObject GetParent(this DependencyObject depObject)
        {
            return VisualTreeHelper.GetParent(depObject);

        }

        public static T GetParent<T>(this DependencyObject depObject)  where T : class
        {

            T searchedParent = null;
            var parent = depObject.GetParent();
            do
            {
                //parent = parent.GetParent()
                searchedParent = parent as T;
                if (searchedParent != null)
                    break;
                else
                    parent = parent.GetParent();
            }
            while (parent != Application.Current.RootVisual);

            return searchedParent;
        }


           
    }
}
